import binascii
import json
import socket
import logging
import select

import redis
# log日志
logging.basicConfig(level = logging.DEBUG,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# 内存
redis = redis.Redis(host='127.0.0.1', port=6379,db=0,password='jizhi@123')

# 数据处理原始数据储存
def recvData(connections,fd,epoll,addresses):

    # 从激活 fd 上接收
    recvData = connections[fd].recv(10240)
    logging.debug("%s---recv event---"%str(addresses[fd]))
    if len(recvData)>0:

        logging.debug('recv:%s'%recvData)
        data = binascii.b2a_hex(recvData)
        logging.debug('b2a_hex:%s'%data)
        data = data.decode(encoding ='utf-8',errors = 'strict')
        logging.debug('utf-8:%s'%data)
        issued = {}
        # 推送
        try:
            issued = recvData.decode(encoding='utf-8',errors='strict')
            logging.debug(issued)
            issued = json.loads(issued)
            logging.debug('issued:%s'%issued)
            if issued['type'] == 'system':
                number = issued['number']
                logging.debug('issued:%s'%number)
                fd2 = redis.get(str(number))
                logging.debug('fd2:%s'%fd2)
                content = issued['code']
                fd2 = fd2.decode(encoding='utf-8', errors='strict')
                connections[int(fd2)].send(binascii.a2b_hex(content))
            else:
                content = '42'
                try:
                    number = issued['number']
                    if len(number) != 0:
                        redis.set(number,fd)
                except BaseException:
                    logging.debug("目标服务器异常！！！不是登录数据！！！")
                    logging.debug('需要解密的数据:%s'%data)
                logging.debug(data)
                logging.debug('fd:%s'%fd)
                connections[fd].send(binascii.a2b_hex(content))
        except BaseException:
            logging.debug('---------服务异常-------------')
    else:
        epoll.unregister(fd)
        connections[fd].close()
        logging.debug('connections:%s'%connections)
        logging.debug('%s---nodata offline---'%str(addresses[fd]))

def main():
    # 创建套接字
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    # 设置可以重复使用绑定的信息
    s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

    # 绑定本机信息
    s.bind(("",8631))

    # 变为被动
    s.listen(10)
    # 非堵塞开启
    # s.setblocking(0)
    # 创建一个epoll对象
    epoll=select.epoll()

    # 测试，用来打印套接字对应的文件描述符
    # print s.fileno()
    # print select.EPOLLIN|select.EPOLLET

    # 注册事件到epoll中
    # epoll.register(fd[, eventmask])
    # 注意，如果fd已经注册过，则会发生异常
    # 将创建的套接字添加到epoll的事件监听中
    # |select.EPOLLET ET模式和LT模式  默认是LT模式
    epoll.register(s.fileno(),select.EPOLLIN)
    connections = {}
    addresses = {}
    # 循环等待客户端的到来或者对方发送数据
    while True:
        # epoll 进行 fd 扫描的地方 -- 未指定超时时间则为阻塞等待
        epoll_list=epoll.poll()
        logging.debug('recv event: {0}'.format(epoll_list))
        # 对事件进行判断
        for fd,events in epoll_list:

            # print fd
            # print events

            # 如果是socket创建的套接字被激活
            if fd == s.fileno():
                conn,addr=s.accept()
                logging.debug('Welcome new client connection%s'%str(addr))
                # 将 conn 和 addr 信息分别保存起来
                connections[conn.fileno()] = conn
                addresses[conn.fileno()] = addr
                logging.debug('connections:%s'%connections)
                # 打开tcpSO_KEEPALIVE选项
                #conn.setsockopt(socket.SOL_SOCKET,socket.SO_KEEPALIVE,True)
                #conn.ioctl(socket.SIO_KEEPALIVE_VALS,(1,20*1000,10*1000))
                # 向 epoll 中注册 连接 socket 的 可读 事件
                epoll.register(conn.fileno(), select.EPOLLIN  | select.EPOLLRDHUP | select.EPOLLHUP | select.EPOLLERR)

            elif events & select.EPOLLIN:
                try:
                    recvData(connections,fd,epoll,addresses)
                except BaseException as e:
                    logging.debug('BaseException:%s'%e)
                if events & select.EPOLLRDHUP:
                    epoll.unregister(fd)
                    connections[fd].close()
                    logging.debug('connections:%s'%connections)
                    logging.debug('%s--- EPOLLRDHUP offline---'%str(addresses[fd]))

            elif events & select.EPOLLHUP:
                epoll.unregister(fd)
                connections[fd].close()
                logging.debug('connections:%s'%connections)
                logging.debug('%s--- EPOLLHUP offline---'%str(addresses[fd]))

            elif events & select.EPOLLRDHUP:
                epoll.unregister(fd)
                connections[fd].close()
                logging.debug('connections:%s'%connections)
                logging.debug('%s--- EPOLLRDHUP offline---'%str(addresses[fd]))

            else:
                epoll.unregister(fd)
                connections[fd].close()
                logging.debug('connections:%s'%connections)
                logging.debug("%s---other error offline---"%str(addresses[fd]))

if __name__ == '__main__':
    main()
